<?php
// +----------------------------------------------------------------------
// | snake
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2022 http://baiyf.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: NickBai <1902822973@qq.com>
// +----------------------------------------------------------------------
namespace app\common\logic;

use think\Db;
use think\Log;

class BaseLogic
{
    protected $tableName = '';
    public function __construct($tableName = ''){
        $this->tableName = $tableName;
    }

    /**
     * 成功返回
     * @param string $msg
     * @param array $data
     */
    protected function retSuccess($msg = '',$data = []){
        if(empty($msg)){
            $msg = '成功';
        }

        return [
            'err_code' => 0,
            'msg' => $msg,
            'data' => $data,
        ];
    }

    /**
     * 错误返回
     * @param string $msg
     * @param string $code 错误代码，自动编号
     */
    protected function retError($msg = '',$code = '1'){
        if(empty($msg)){
            $msg = '错误';
        }
//        $backtrace = debug_backtrace();
//        array_shift($backtrace);
//        $codes = [];
//        $logs = [];
//        foreach ($backtrace as $item){
//            $class = explode('\\',$item['class']);
//            // 不是自己开发的
//            if('app' != $class[0]){
//                break;
//            }
//            $error_code = config('error_code.'.$item['class']);
//            if(empty($error_code)){
//                // 未设置 用 XXXX 代替
//                $error_code = 'XXXX';
//            }
//            if(!empty($item['line'])){
//                $codes[] = $error_code . str_pad($item['line'],4,'0',STR_PAD_LEFT);
//            }
//            $logs[] = $item;
//        }

        // 写入日志
//        \think\facade\Log::warning('retError 错误：' . json_encode($logs,256));

        return [
            'err_code' => $code,
            'msg' => $msg,
            'data' => [],
        ];
    }

    /**
     * 检测表名是否传入
     * @param $tableName
     * @return string
     * @throws \Exception
     */
    private function checkTableName($tableName){
        if(empty($tableName)){
            $tableName = $this->tableName;
        }

        if(empty($tableName)){
            exception('tableName 表名 不能为空');
        }

        return $tableName;
    }

    /**
     * @param $where
     * @param int $limit
     * @param string $order
     * @param int $isDel
     * @param string $tableName
     * @return array|\PDOStatement|string|\think\Collection
     * @throws \Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getAllListByWhere(array $where, $limit = 0,$order = '',$isDel = 0,$tableName = ''){
        return $this->_getListByWhere($where,0,$limit,$order,$isDel,$tableName);
    }
    /**
     * @param $where
     * @param int $offset
     * @param int $limit
     * @param string $order
     * @param int $isDel
     * @param string $tableName
     * @return array|\PDOStatement|string|\think\Collection
     * @throws \Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getListByWhere(array $where, $offset = 0, $limit = 0,$order = '',$isDel = 0,$tableName = '')
    {
        $tableName = $this->checkTableName($tableName);
        $tableDb = Db::name($tableName);
        $orm = model($tableName);
        if(!empty($orm->softDel)){
            //带软删除 $isDel = 1 查询出已经删除了的数据
            if(!empty($isDel)){
                $where[] = [$orm->softDel,'>',0];
            }
            else{
                $where[] = [$orm->softDel,'<',1];
            }
        }
        $tableDb->where($where)->order($order);

        if($limit > 0){
            $tableDb->limit($offset, $limit);
        }

        return $tableDb->select();
    }

    /**
     * 获取 指定表 指定条件 的条数
     * @param array $where
     * @param int $isDel
     * @param string $tableName
     * @return int|string
     * @throws \Exception
     */
    public function _getCountByWhere(array $where = [],$isDel = 0,$tableName = ''){
        $tableName = $this->checkTableName($tableName);
        $tableDb = Db::name($tableName);
        $orm = model($tableName);
        if(!empty($orm->softDel)){
            //带软删除
            if(!empty($isDel)){
                $where[] = [$orm->softDel,'>',0];
            }
            else{
                $where[] = [$orm->softDel,'<',1];
            }
        }
        return $tableDb->where($where)->count();
    }

    /**
     * 按条件返回列表
     * @param \think\db\Query $queryWhere
     * @param int $offset
     * @param int $limit
     * @param string $order
     * @param int $isDel
     * @param string $tableName
     * @return array|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getListByQueryWhere(\think\db\Query $queryWhere, $offset = 0, $limit = 0,$order = '',$isDel = 0,$tableName = '')
    {
        $tableName = $this->checkTableName($tableName);
        $tableDb = Db::name($tableName);
        $orm = model($tableName);
        if(!empty($orm->softDel)){
            //带软删除 $isDel = 1 查询出已经删除了的数据
            if(!empty($isDel)){
                $queryWhere->where($orm->softDel,'>',0);
            }
            else{
                $queryWhere->where($orm->softDel,'<',1);
            }
        }
        $tableDb->where($queryWhere)->order($order);

        if($limit > 0){
            $tableDb->limit($offset, $limit);
        }

        return $tableDb->select();
    }

    /**
     * 按条件 查询 个数
     * @param \think\db\Query $queryWhere
     * @param int $isDel
     * @param string $tableName
     * @return float|string
     * @throws \Exception
     */
    public function _getCountByQueryWhere(\think\db\Query $queryWhere,$isDel = 0,$tableName = ''){
        $tableName = $this->checkTableName($tableName);
        $tableDb = Db::name($tableName);
        $orm = model($tableName);
        if(!empty($orm->softDel)){
            //带软删除
            if(!empty($isDel)){
                $queryWhere->where($orm->softDel,'>',0);
            }
            else{
                $queryWhere->where($orm->softDel,'<',1);
            }
        }
        return $tableDb->where($queryWhere)->count();
    }

    /**
     * 获取 指定表 指定条件 的条数 （原始，不自动添加删除条件）
     * @param array $where
     * @param string $tableName
     * @return float|string
     */
    public function _getCountByOriginalWhere(array $where = [],$tableName = ''){
        $tableDb = Db::name($tableName);
        return $tableDb->where($where)->count();
    }

    /**
     * 取分页
     * @param \think\db\Query $queryWhere
     * @param int $pageIndex
     * @param int $pageSize
     * @param string $order
     * @param int $isDel
     * @param string $tableName
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getPagerByQueryWhere(\think\db\Query $queryWhere, $pageIndex = 1, $pageSize = 50,$order = '',$isDel = 0,$tableName = '')
    {
        $tableName = $this->checkTableName($tableName);
        $tableDb = Db::name($tableName);
        $orm = model($tableName);
        if(!empty($orm->softDel)){
            //带软删除 $isDel = 1 查询出已经删除了的数据
            if(!empty($isDel)){
                $queryWhere->where($orm->softDel,'>',0);
            }
            else{
                $queryWhere->where($orm->softDel,'<',1);
            }
        }
        $tableDb->where($queryWhere)->order($order);

        $tableDb->page($pageIndex, $pageSize);

        $totalRows = $tableDb->count();
        $dataList = $tableDb->select();

        return [
            'list' => $dataList,
            'pageInfo' => [
                'pageIndex' => $pageIndex,
                'pageSize' => $pageSize,
                'totalRows' => $totalRows,
                'totalPager' => ceil($totalRows / $pageSize),
            ],
        ];
    }

    /**
     * 按Pk 获取 指定表的 某 列 或者一条数据，自动判断软删除 ， 由 $field参数指定
     * @param integer $id 外键
     * @param string|boolean $field true 获取整条数据 其他请填写 字段名称
     * @param string $tableName 不填则使用 初始化 时传入的表名
     * @param bool $isWithCache 是否从缓存里面读取
     * @return mixed|string
     * @throws \Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getFieldOrModelById($id,$field,$tableName = '',$isWithCache = false){
        $tableName = $this->checkTableName($tableName);
        if(false === $isWithCache){
            $dataList = [];
        }
        else{
            $dataList = cache($tableName.'_getFieldOrModelWithCacheById','',null,'model');
        }

        if(empty($dataList)){
            $where = [];
            $orm = model($tableName);
            if(!empty($orm->softDel)){
                //带软删除
                $where[] = [$orm->softDel,'<',1];
            }
            $dataList = Db::name($tableName)->where($where)->select();
            if(true === $isWithCache){
                cache($tableName.'_getFieldOrModelWithCacheById',$dataList,600,'model');
            }
        }

        $data = '';
        $pkName = Db::name($tableName)->getPk();
        foreach ($dataList as $item){
            if($item[$pkName] == $id){
                if(true === $field){
                    return $item;
                }
                else{
                    $data = $item[$field];
                }
                break;
            }
        }

        if(empty($data)){
            return '';
        }
        else{
            return $data;
        }
    }

    /**
     * @param $id
     * @param string $tableName
     * @return mixed|string
     * @throws \Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function getModelByPk($id,$tableName = ''){
        return $this->retSuccess('成功',$this->_getFieldOrModelById($id,true,$tableName));
    }

    public function _getModelByOriginalWhere($where,$tableName,$order = ''){
        return Db::name($tableName)->where($where)->order($order)->find();
    }

    public function _getValue($where,$colum,$tableName,$order = ''){
        return Db::name($tableName)->where($where)->order($order)->value($colum);
    }

    /**
     * 设置某列的值
     * @param $pk
     * @param $field
     * @param $val
     * @param string $tableName
     * @return array
     * @throws \Exception
     */
    public function setField($pk,$field,$val,$tableName = ''){
        $tableName = $this->checkTableName($tableName);
        $jieguo = Db::name($tableName)->where('id',$pk)->setField($field,$val);

        if($jieguo !== false){
            return $this->retSuccess('设置成功');
        }
        else{
            return $this->retError('设置失败');
        }
    }

    public function setFieldByWhere($where,$data,$tableName = ''){
        $tableName = $this->checkTableName($tableName);
        $jieguo = Db::name($tableName)->where($where)->setField($data);

        if($jieguo !== false){
            return $this->retSuccess('设置成功');
        }
        else{
            return $this->retError('设置失败');
        }
    }

    /**
     * 保存数据（注意使用本方法必须新建好model），新增修改都使用本方法，自动判断新增还是修改，自动过滤非本表字段
     * @param $param
     * @param string $tableName
     * @return array
     * @throws \Exception
     */
    public function save(array $param,$tableName = '')
    {
        $tableName = $this->checkTableName($tableName);
        $tableDb = Db::name($tableName);
        $pkName = $tableDb->getPk();
        try{
            $pkId = $param[$pkName];
            $model = model($tableName);
            $updateWhere = [];

            //清除空格
            foreach ($param as &$item){
                if(is_string($item)){
                    $item = trim($item);
                }
            }
            unset($item);

            // 去掉数据表字段不存在的参数
            $tableFields = $model->getTableFields();
            $data = [];
            foreach ($tableFields as $field){
                // 检测是否传入
                if(array_key_exists($field,$param)){
                    $data[$field] = $param[$field];
                }
            }

            $successText = '';

            if($pkId > 0){
                $updateWhere = [$pkName => $param[$pkName]];
                // 搜索表 判断是 添加还是更新，如果 主键大于 0 的情况
                if($model->where($updateWhere)->count() > 0){
                    // 去掉 主键
                    unset($data[$pkName]);
                    // 通过旧值判断某些字段是否需要更新
                    foreach ($data as $key => $item){
                        if(!empty($param['original_' . $key])){
                            // 先比对长度是否相等 内容绝对相等 成立 去掉更新字段
                            if(strlen($param['original_' . $key]) === strlen($data[$key]) && $param['original_' . $key] === $data[$key]){
                                unset($data[$key]);
                            }
                        }
                    }

                    // 判断是否有编辑时间
                    if(property_exists($model,'updateTime')){
                        if(!empty($model->updateTime)){
                            $data[$model->updateTime] = time();
                        }
                    }
                    $result =  $model->allowField(true)->save($data, $updateWhere);

                    $successText = '编辑';
                }
                else{
                    $result = $this->save_insert($model,$param,$pkName,$data);
                    $successText = '添加';
                }
            }
            else{
                // 添加
                $result = $this->save_insert($model,$param,$pkName,$data);
                $successText = '添加';
            }
            if(false === $result){
                // 验证失败 输出错误信息
                return $this->retError($model->getError());
            }else{
                return $this->retSuccess($successText . '成功',$param);
            }
        }catch( \PDOException $e){
            return $this->retError($e->getMessage());
        }
    }

    private function save_insert(&$model,&$param,$pkName,$data){
        // 判断是否有添加时间
        if(property_exists($model,'createTime')){
            if(!empty($model->createTime)){
                $data[$model->createTime] = time();
            }
        }
        $pkId =  $model->allowField(true)->insertGetId($data);
        // 判断是否指定 主键，如果已经指定则默认成功
        if(!empty($param[$pkName]) && $param[$pkName] > 0){
            return true;
        }
        else{
            $param[$pkName] = $pkId;
            return $pkId > 0;
        }
    }

    /**
     * 删除（注意使用本方法必须新建好model），自动判断model配置是否为软删除
     * @param $id
     * @param string $tableName
     * @return array
     * @throws \Exception
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function del($id,$tableName = '')
    {
        $tableName = $this->checkTableName($tableName);
        $tableDb = Db::name($tableName);
        $pkName = $tableDb->getPk();
        try{
            $orm = model($tableName);
            if(!empty($orm->softDel)){
                //带软删除
                $result = $tableDb->where($pkName, $id)->setField($orm->softDel,time());
            }
            else{
                $result = $tableDb->where($pkName, $id)->delete();
            }
            if(false !== $result){
                return $this->retSuccess('删除成功');
            }
            else{
                return $this->retError('删除失败');
            }
        }catch( \PDOException $e){
            return $this->retError($e->getMessage());
        }
    }

    /**
     * 读取数据库里面的全局设置 ， 写入设置，带 缓存
     * @return mixed array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getSiteConfigAllList($projectId){
        $cacheKey = 'BaseLogic_getSiteConfigAllList_' . $projectId;
        $configs = cache($cacheKey,'',null,'system');
        if (empty($configs)) {
            $sysLogic = new SysLogic();
            $configs = $sysLogic->_getProjectConfig($projectId);
            cache($cacheKey, $configs, 86400,'system');
        }

        return $configs;
    }
}